/*************************************************************************//**
 *****************************************************************************
 * @file   main.c
 * @brief  
 * @author Forrest Y. Yu
 * @date   2007
 *****************************************************************************
 *****************************************************************************/

#include "type.h"
#include "config.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"

#include "hd.h"

PRIVATE void init_fs();


/*new FS*/
PRIVATE void readSuperBlock(int dev);
PUBLIC struct m_inode * iget(int dev, int nr);
struct m_inode inodeTable[32]={{0,},};

/*****************************************************************************
 *                                task_fs
 *****************************************************************************/
/**
 * <Ring 1> The main loop of TASK FS.
 * 
 *****************************************************************************/
PUBLIC void task_fs()
{
//	printl("Task FS begins.\n");

	init_fs();

	while (1) {
		send_recv(RECEIVE, ANY, &fs_msg);

		int src = fs_msg.source;
		pcaller = &proc_table[src];

		switch (fs_msg.type) {
		case OPEN:
			fs_msg.FD = new_open();
			break;
		case CLOSE:
			fs_msg.RETVAL = do_close();
			break;
		case READ:
			fs_msg.CNT = new_file_read();
			break;
		case WRITE:
			//fs_msg.CNT = do_rdwt();
			break;
		case LIST:
			fs_msg.CNT = handle_list();
			break;

		default:
			dump_msg("FS::unknown message:", &fs_msg);
			assert(0);
			break;
		}

		/* reply */
		fs_msg.type = SYSCALL_RET;
		send_recv(SEND, src, &fs_msg);
	}
}

/*****************************************************************************
 *                                init_fs
 *****************************************************************************/
/**
 * <Ring 1> Do some preparation.
 * 
 *****************************************************************************/
PRIVATE void init_fs()
{
	int i;



	/* inodeTable initial */
	for (i = 0; i < NR_INODE; i++)
		memset(&inodeTable[i], 0, sizeof(struct m_inode));

	for (i = 0; i < 32; i++)
		memset(&fileTable[i], 0, sizeof(struct file));


	/* open the device: hard disk */
	MESSAGE driver_msg;
	driver_msg.type = DEV_OPEN;
	driver_msg.DEVICE = MINOR(ROOT_DEV);
	assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
	send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);

	/*get new superblock*/
	readSuperBlock(0x301);
	root = iget(0x301,1);
	pwd = root;
	new_open();
	//printl("inode mode: %d",inode->i_mode);
	
	//printl("inode time: %d",inode->i_mtime);
	/* make FS */
//	mkfs();

	/* load super block of ROOT */
//	read_super_block(ROOT_DEV);

//	sb = get_super_block(ROOT_DEV);
//	assert(sb->magic == MAGIC_V1);

//	root_inode = get_inode(ROOT_DEV, ROOT_INODE);
}

PRIVATE void readSuperBlock(int dev)
{
	struct superBlock * s;
	
	s = &onlySuper;
	
	printl("the magic of os : %d\n",s->s_magic);
	printl("the root_dev of os : %d\n",dev);
	
		
	new_read(dev, 1);

	*((struct d_superBlock *) s) =
		*((struct d_superBlock *)fsbuf);
	if (s->s_magic != SUPER_MAGIC) {
		printl("falseSUPER_MAGIC\n");
		printl("the magic of os : %d",s->s_magic);
		printl("the magic of os : %d",s->s_ninodes);
		printl("the magic of os : %d",s->s_nzones);

	}
	else{
		printl("read superblocksuccess\n");
		printl("the magic of os : %d",s->s_ninodes);
		printl("the magic of os : %d",s->s_nzones);
	}
	
}

PUBLIC struct m_inode * iget(int dev, int nr)
{
	/*没有考虑多进程，假设一定能获取的到*/
	struct m_inode * inode;
	static struct m_inode * last_inode = inodeTable;
	int block;
	int i;
	if(!nr)
		return NULL;
	for (i = NR_INODE; i ; i--) {
		if (++last_inode >= inodeTable + NR_INODE)
			last_inode = inodeTable;
		if (!last_inode->i_count) {
			inode = last_inode;
		if (!inode->i_dirt && !inode->i_lock)
			break;
		}
	}
	if(!inode)
		printl("no inode get");
	inode->i_dev = dev;
	inode->i_num = nr;
	/*inode is empty, now read new inode */
	struct superBlock * sb = &onlySuper;
	block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
		(inode->i_num-1)/INODES_PER_BLOCK;
	new_read(dev,block);
	*(struct d_inode *)inode =
		((struct d_inode *)fsbuf)
			[(inode->i_num-1)%INODES_PER_BLOCK];
	inode->i_count++;
	return inode;
		
}
PUBLIC void iput(struct m_inode * inode)
{
	inode->i_count--;
}
PUBLIC void new_read(int dev, int block)
{
	MESSAGE driver_msg;
	driver_msg.type		= DEV_READ;
	driver_msg.DEVICE	= MINOR(dev);
	driver_msg.POSITION	= block*2;
	driver_msg.BUF		= fsbuf;
	driver_msg.CNT		= 2;
	driver_msg.PROC_NR	= TASK_FS;
	assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
	send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
		

}


